﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
//using Microsoft.CodeAnalysis.MSBuild;

namespace CodeFound
{
    class Program
    {
        public void Test()
        {
            //Workspace workspace = null;
            //SemanticModel model = null;
            //MSBuildWorkspace msbw = MSBuildWorkspace.Create();
            
            //msbw.CanApplyChange(ApplyChangesKind.AddDocument);
            
            //Document doc = workspace.CurrentSolution.Projects.First().Documents.First();
            //doc.TryGetSemanticModel(out model);
            //SyntaxNode root = null;
            //doc.TryGetSyntaxRoot(out root);
            //var classData= root.DescendantNodes().OfType<ClassDeclarationSyntax>().First();
            //var classSy = model.GetDeclaredSymbol(classData);
            //List<DeclareData> listData = new List<CodeFound.Program.DeclareData>();
            //GetAllFieldsAndPropertys(classSy, listData);
            

        }
        public string a;
        public int b;
        public bool c { get; set; }
        static void Main(string[] args)
        {
            SyntaxTree tree = CSharpSyntaxTree.ParseText(
                @"using System;
                using System.Text;
                namespace HelloWorld
                {
                    public class Programe:Controller
                    {
                        public float c;
                        public bool d{get;set;}
                        static void Main(string[] args)
                        {
                            int l1;
                            float l2;
                            Console.WriteLine(""Hello World!"");
                        }
                    }
                }");
            SyntaxTree baseTree = CSharpSyntaxTree.ParseText(
                @"using System;
                namespace HelloWorld
                {
                    public class Controller:Maigic
                    {
                        public int a;
                        public string b;
                    }
                }");
            SyntaxTree sigTree = CSharpSyntaxTree.ParseText(
                @"using System;
                namespace HelloWorld
                {
                    public class Maigic
                    {
                        public Maigic m;
                        public int a2;
                        public string b2;
                    }
                }"
                );
            var root = (CompilationUnitSyntax)tree.GetRoot();
            var compilation = CSharpCompilation.Create("HelloWorld").AddReferences(MetadataReference.CreateFromFile(typeof(object).Assembly.Location)).AddSyntaxTrees(tree,baseTree,sigTree);
            var model = compilation.GetSemanticModel(tree);
            var nameInfo = model.GetSymbolInfo(root.Usings[0].Name);
            var systemSymbol = (INamespaceSymbol)nameInfo.Symbol;
            foreach (var ns in systemSymbol.GetNamespaceMembers())
            {
                Console.WriteLine(ns.Name);
            }
            var helloWorldString = root.DescendantNodes().OfType<LiteralExpressionSyntax>().First();
            var literalInfo = model.GetTypeInfo(helloWorldString);
            Console.Clear();
            var stringTypeSymbol = (INamedTypeSymbol)literalInfo.Type;
            foreach (var name in (from method in stringTypeSymbol.GetMembers().OfType<IMethodSymbol>()
                                  where method.ReturnType.Equals(stringTypeSymbol) && method.DeclaredAccessibility == Accessibility.Public
                                  select method.Name).Distinct())
            {
                Console.WriteLine(name);
            }
            Console.Clear();
            StringWriter structString = new StringWriter();
            var action = root.DescendantNodes().OfType<ClassDeclarationSyntax>().First();
            var actionSy= model.GetDeclaredSymbol(action);
            List<DeclareData> datas = new List<DeclareData>();
            GetAllFieldsAndPropertys(actionSy, datas);
            
            var methodT = root.DescendantNodes().OfType<MethodDeclarationSyntax>().First();//.Body.DescendantNodes().OfType<LocalDeclarationStatementSyntax>();
            GetLocalVars(methodT, model, datas);
            BuildStruct(Console.Out,"NewF","Model", datas);
            //var actionInfo= model.GetSymbolInfo(controller);
            //var fields= actionInfo.Type.GetMembers().OfType<IFieldSymbol>();
            //foreach (var field in fields)
            //{
            //    Console.WriteLine(field.Name+field.Type);
            //}
            Console.ReadKey();
        }
        public struct DeclareData
        {
            public string Type;
            public string Name;
            public bool IsAttribute;
            public override string ToString()
            {
                if (IsAttribute)
                {
                    return $"\t{Type} {Name} {{get;set;}}";
                }
                else
                {
                    return $"\t{Type} {Name};";
                }
            }
        }
        public static void BuildStruct(TextWriter tw,string nameSpace,string className,IList<DeclareData> declares)
        {
            tw.WriteLine("using System;");
            tw.WriteLine("//NFinal自动生成Model类");
            tw.Write("namespace ");
            tw.WriteLine(nameSpace);
            tw.WriteLine("{");
            tw.Write("\tpublic struct ");
            tw.WriteLine(className);
            tw.WriteLine("\t{");
            foreach (var de in declares)
            {
                tw.Write("\t\t");
                tw.Write(de.Type);
                tw.Write(" ");
                tw.Write(de.Name);
                if (de.IsAttribute)
                {
                    tw.WriteLine("{get;set;}");
                }
                else
                {
                    tw.WriteLine(";");
                }
            }
            tw.WriteLine("\t}");
            tw.WriteLine("}");
        }
        public static void GetLocalVars(MethodDeclarationSyntax methodT,SemanticModel model,IList<DeclareData> declares)
        {
            var methodSy = model.GetDeclaredSymbol(methodT);
            ILocalSymbol localSy = null;
            DeclareData data;
            foreach (var declear in methodT.Body.DescendantNodes().OfType<LocalDeclarationStatementSyntax>())
            {
                foreach (var declearVar in declear.Declaration.Variables)
                {
                    localSy = (ILocalSymbol)model.GetDeclaredSymbol(declearVar);
                    data.IsAttribute = false;
                    data.Type = localSy.Type.OriginalDefinition.ToString();
                    data.Name = localSy.Name;
                    declares.Add(data);
                }
            }
        }
        public static void GetAllFieldsAndPropertys(INamedTypeSymbol symbol,IList<DeclareData> declares)
        {
            if (symbol != null)
            {
                DeclareData data;
                foreach (var filed in symbol.GetMembers().OfType<IFieldSymbol>())
                {
                    if (filed.CanBeReferencedByName)
                    {
                        data.IsAttribute = false;
                        data.Type = filed.Type.OriginalDefinition.ToString();
                        data.Name = filed.Name;
                        declares.Add(data);
                    }
                }
                foreach (var property in symbol.GetMembers().OfType<IPropertySymbol>())
                {
                    data.IsAttribute = true;
                    data.Type = property.Type.OriginalDefinition.ToString();
                    data.Name = property.Name;
                    declares.Add(data);
                }
            }
            if (symbol.BaseType != null)
            {
                GetAllFieldsAndPropertys(symbol.BaseType, declares);
            }
        }

    }
}
